package visao;


import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeSet;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSeparator;
import javax.swing.JTextField;

import logica.Atomo;
import logica.CalculoProposicional;
import logica.Formula;
import logica.InterpretadorDeFormula;
import controle.Main;

public class JanelaPrincipal extends JFrame implements ActionListener
{
	private static final long serialVersionUID = 1L;
	private JTextField txtFormula;
	private JPanel panel_valores;
	private JButton btnTrocar;
	private JButton btnValorarFrmula;
	private JButton btnTodosParaFalso;
	private JButton btnTodosParaVerdade;
	private JLabel lblStatus;
	private JProgressBar progressBar;
	
	private JMenuItem mntmLerDadosDe;
	private JMenuItem mntmSalvarDados;
	private JMenuItem mntmSair;
	private JMenuItem mntmLimparFrmula;
	private JMenuItem mntmTrocarFrmula;
	private JMenuItem mntmEditarSmbolos;
	private JMenuItem mntmConfigurarVariveis;
	private JMenuItem mntmComoUsar;
	private JMenuItem mntmSobre;
	private JMenuItem mntmValorarFrmula;
	private JMenuItem mntmVerArvore;
	
	//dados de logica
	private Formula formulaAtual;
	private CalculoProposicional calculoProposicionalAtual = new CalculoProposicional();
	private JLabel lblVersao;
	
	public JanelaPrincipal()
	{
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setTitle("Programa de Lógica Caqui");
		setIconImage(new ImageIcon("img/caqui_icone.png").getImage());
		setSize(new Dimension(640, 480));
		
		JPanel panel_formula = new JPanel();
		getContentPane().add(panel_formula, BorderLayout.NORTH);
		panel_formula.setLayout(new BoxLayout(panel_formula, BoxLayout.Y_AXIS));
		
		Component rigidArea = Box.createRigidArea(new Dimension(20, 20));
		rigidArea.setPreferredSize(new Dimension(20, 5));
		panel_formula.add(rigidArea);
		
		JPanel panel_4 = new JPanel();
		FlowLayout flowLayout = (FlowLayout) panel_4.getLayout();
		flowLayout.setAlignment(FlowLayout.LEADING);
		panel_formula.add(panel_4);
		
		JLabel lblFrmula = new JLabel("Fórmula:");
		panel_4.add(lblFrmula);
		
		Component rigidArea_3 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_3.setPreferredSize(new Dimension(12, 5));
		panel_formula.add(rigidArea_3);
		
		JPanel panel_1 = new JPanel();
		panel_formula.add(panel_1);
		panel_1.setLayout(new BoxLayout(panel_1, BoxLayout.X_AXIS));
		
		Component rigidArea_1 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_1.setPreferredSize(new Dimension(5, 20));
		panel_1.add(rigidArea_1);
		
		txtFormula = new JTextField();
		txtFormula.setEditable(false);
		panel_1.add(txtFormula);
		txtFormula.setMargin(new Insets(8, 8, 8, 8));
		txtFormula.setColumns(10);
		
		Component rigidArea_5 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_5.setPreferredSize(new Dimension(5, 20));
		panel_1.add(rigidArea_5);
		
		btnTrocar = new JButton("Trocar");
		btnTrocar.addActionListener(this);
		btnTrocar.setPreferredSize(new Dimension(96, 28));
		panel_1.add(btnTrocar);
		
		Component rigidArea_2 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_2.setPreferredSize(new Dimension(5, 20));
		panel_1.add(rigidArea_2);
		
		Component rigidArea_8 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_8.setPreferredSize(new Dimension(20, 5));
		panel_formula.add(rigidArea_8);
		
		JPanel panel_status = new JPanel();
		getContentPane().add(panel_status, BorderLayout.SOUTH);
		panel_status.setLayout(new BoxLayout(panel_status, BoxLayout.X_AXIS));
		
		Component rigidArea_4 = Box.createRigidArea(new Dimension(20, 20));
		panel_status.add(rigidArea_4);
		
		progressBar = new JProgressBar();
		progressBar.setPreferredSize(new Dimension(64, 14));
		progressBar.setAlignmentX(Component.LEFT_ALIGNMENT);
		panel_status.add(progressBar);
		
		JPanel panel_5 = new JPanel();
		panel_status.add(panel_5);
		panel_5.setLayout(new BoxLayout(panel_5, BoxLayout.X_AXIS));
		
		Component horizontalStrut = Box.createHorizontalStrut(20);
		horizontalStrut.setPreferredSize(new Dimension(10, 0));
		panel_5.add(horizontalStrut);
		
		lblStatus = new JLabel("Parado");
		panel_5.add(lblStatus);
		
		Component horizontalGlue = Box.createHorizontalGlue();
		panel_5.add(horizontalGlue);
		
		lblVersao = new JLabel(Main.VERSAO);
		panel_5.add(lblVersao);
		
		JPanel panel_central = new JPanel();
		getContentPane().add(panel_central, BorderLayout.CENTER);
		panel_central.setLayout(new BorderLayout(0, 0));
		
		JScrollPane scrollPane = new JScrollPane();
		panel_central.add(scrollPane);
		
		panel_valores = new JPanel();
		panel_valores.setLayout(new BoxLayout(panel_valores, BoxLayout.Y_AXIS));
		scrollPane.setViewportView(panel_valores);
		atualizaCheckboxes(false);
		
		JPanel panel_botoes = new JPanel();
		panel_central.add(panel_botoes, BorderLayout.SOUTH);
		
		btnValorarFrmula = new JButton("Valorar fórmula");
		btnValorarFrmula.addActionListener(this);
		panel_botoes.add(btnValorarFrmula);
		
		btnTodosParaFalso = new JButton("Todos para falso");
		btnTodosParaFalso.addActionListener(this);
		panel_botoes.add(btnTodosParaFalso);
		
		btnTodosParaVerdade = new JButton("Todos para verdade");
		btnTodosParaVerdade.addActionListener(this);
		panel_botoes.add(btnTodosParaVerdade);
		
		Component rigidArea_6 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_6.setPreferredSize(new Dimension(5, 20));
		getContentPane().add(rigidArea_6, BorderLayout.WEST);
		
		Component rigidArea_7 = Box.createRigidArea(new Dimension(20, 20));
		rigidArea_7.setPreferredSize(new Dimension(5, 20));
		getContentPane().add(rigidArea_7, BorderLayout.EAST);
		
		setLocationRelativeTo(null);
		
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		JMenu mnArquivo = new JMenu("Arquivo");
		menuBar.add(mnArquivo);
		
		mntmLerDadosDe = new JMenuItem("Ler dados de arquivo");
		mntmLerDadosDe.setEnabled(false);
		mntmLerDadosDe.addActionListener(this);
		mnArquivo.add(mntmLerDadosDe);
		
		mntmSalvarDados = new JMenuItem("Salvar dados");
		mntmSalvarDados.setEnabled(false);
		mntmSalvarDados.addActionListener(this);
		mnArquivo.add(mntmSalvarDados);
		
		mntmSair = new JMenuItem("Sair");
		mntmSair.addActionListener(this);
		mnArquivo.add(mntmSair);
		
		JMenu mnEditar = new JMenu("Editar");
		menuBar.add(mnEditar);
		
		mntmLimparFrmula = new JMenuItem("Limpar fórmula");
		mntmLimparFrmula.addActionListener(this);
		mnEditar.add(mntmLimparFrmula);
		
		mntmTrocarFrmula = new JMenuItem("Trocar fórmula");
		mntmTrocarFrmula.addActionListener(this);
		mnEditar.add(mntmTrocarFrmula);
		
		JSeparator separator = new JSeparator();
		mnEditar.add(separator);
		
		mntmEditarSmbolos = new JMenuItem("Configurar operadores");
		mntmEditarSmbolos.setEnabled(false);
		mntmEditarSmbolos.addActionListener(this);
		mnEditar.add(mntmEditarSmbolos);
		
		mntmConfigurarVariveis = new JMenuItem("Configurar variáveis");
		mntmConfigurarVariveis.setEnabled(false);
		mntmConfigurarVariveis.addActionListener(this);
		mnEditar.add(mntmConfigurarVariveis);
		
		JMenu mnFerramentas = new JMenu("Ferramentas");
		menuBar.add(mnFerramentas);
		
		mntmValorarFrmula = new JMenuItem("Valorar fórmula");
		mntmValorarFrmula.addActionListener(this);
		mnFerramentas.add(mntmValorarFrmula);
		
		mntmVerArvore = new JMenuItem("Ver árvore de fórmulas");
		mntmVerArvore.setEnabled(false);
		mntmVerArvore.addActionListener(this);
		mnFerramentas.add(mntmVerArvore);
		
		JMenu mnAjuda = new JMenu("Ajuda");
		menuBar.add(mnAjuda);
		
		mntmComoUsar = new JMenuItem("Como usar");
		mntmComoUsar.setEnabled(false);
		mntmComoUsar.addActionListener(this);
		mnAjuda.add(mntmComoUsar);
		
		mntmSobre = new JMenuItem("Sobre");
		mntmSobre.addActionListener(this);
		mnAjuda.add(mntmSobre);
		
		setVisible(true);
	}

	@Override
	public void actionPerformed(ActionEvent arg0) 
	{
		Object source = arg0.getSource();
		
		if(source == null)
			return;
		
		else if(source == btnTrocar || source == mntmTrocarFrmula)
		{
			trocarFormula();
		}
		
		else if(source == btnTodosParaFalso)
		{
			atualizaCheckboxes(false);
		}
		
		else if(source == btnTodosParaVerdade)
		{
			atualizaCheckboxes(true);
		}
		
		else if(source == btnValorarFrmula || source == mntmValorarFrmula)
		{
			valorarFormula();
		}
		
		else if(source == mntmSair)
		{
			this.dispose();
		}
		
		else if(source == mntmLimparFrmula)
		{
			txtFormula.setText("");
			formulaAtual = null;
		}
		
		else if(source == mntmSobre)
		{
			String texto="\nPrograma de Lógica Caqui \n"
					+ "por Carlos F. M. Faruolo \n"
					+ "<5carlosfelipe5@gmail.com> \n\n"
					+ "Versão "+Main.VERSAO;
			JOptionPane.showMessageDialog(this, texto, "Sobre Caqui", JOptionPane.INFORMATION_MESSAGE, new ImageIcon("img/caqui_sobre.png"));
		}
		
	}
	
	private void atualizaCheckboxes(boolean opcao)
	{
		panel_valores.removeAll();
		
		//queremos uma lista ordenada, para não ficar "feio"
		List<Atomo> lista = new ArrayList<Atomo>(calculoProposicionalAtual.simbolosProposicionais);
		Collections.sort(lista);
		
		for(Atomo c : lista)
		{
			panel_valores.add(new JCheckBox(c.rotulo+" verdadeiro", opcao));
		}
		panel_valores.validate();
	}
	
	private void trocarFormula()
	{
		String expressao;
		expressao = JOptionPane.showInputDialog(this, "Entre com a formula nova", "Trocar formula", JOptionPane.QUESTION_MESSAGE);
		if(expressao != null)
		{
			if(expressao.trim().equals(""))
			{
				JOptionPane.showMessageDialog(this, "Campo vazio! Digite uma formula", "Campo vazio", JOptionPane.WARNING_MESSAGE);
			}
			try
			{
				lblStatus.setText("Interpretando...");
				InterpretadorDeFormula interprete = new InterpretadorDeFormula(calculoProposicionalAtual);
				formulaAtual = interprete.interpretar(expressao.trim());
				lblStatus.setText("Parado");
//				System.out.println(f.toString());
				txtFormula.setText(expressao.trim());
				JOptionPane.showMessageDialog(this,"O interpretador reconheceu a expressao \""+expressao+"\" com sucesso!", "Sucesso!", JOptionPane.INFORMATION_MESSAGE);
			}
			catch(Exception e)
			{
				JOptionPane.showMessageDialog(this, e.getMessage()+"\n Tente novamente!", "Erro!", JOptionPane.ERROR_MESSAGE);
			}
		}
	}
	
	private void valorarFormula()
	{
		if(formulaAtual == null)
		{
			trocarFormula();
			if(formulaAtual == null)
				return;
		}
			
		lblStatus.setText("Valorando fórmula...");
		Map<Atomo, Boolean> valores = new HashMap<Atomo, Boolean>();
		for(Component c : panel_valores.getComponents())
		{
			JCheckBox check = (JCheckBox) c;
			valores.put(new Atomo(check.getText().charAt(0)), check.isSelected());
		}
		
		try 
		{
			boolean resultado = formulaAtual.valorar(valores);
			if(resultado == true)
				JOptionPane.showMessageDialog(this, "Verdade");
			else
				JOptionPane.showMessageDialog(this, "Falso");
		} 
		catch (Exception e) 
		{
			JOptionPane.showMessageDialog(this, "Erro ao valorar fórmula. "+e.getLocalizedMessage(), "Erro", JOptionPane.ERROR_MESSAGE);
		}
		lblStatus.setText("Parado");
	}
	
	private File escolheArquivoParaLer()
	{
		JFileChooser colhedor = new JFileChooser();
		colhedor.setMultiSelectionEnabled(false);
		colhedor.showOpenDialog(this);
		return colhedor.getSelectedFile();
	}
	
	/** Nao usar, nao esta pronto. */
	@Deprecated
	private void lerArquivo(File file)
	{
		Scanner scan = null;
		try 
		{
			scan = new Scanner(file);
		} 
		catch (FileNotFoundException e) 
		{
			JOptionPane.showMessageDialog(this, "Arquivo não pode ser aberto. "+e.getLocalizedMessage(), "Erro", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		if( ! scan.hasNext())
		{
			JOptionPane.showMessageDialog(this, "Arquivo inválido! Cabeçalho ausente!", "Erro", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		String cabecalho = scan.next();
		
		if( ! cabecalho.equalsIgnoreCase(Main.CABECALHO_ARQUIVO))
		{
			JOptionPane.showMessageDialog(this, "Arquivo inválido! Cabeçalho inválido!", "Erro", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		if( ! scan.hasNext())
		{
			JOptionPane.showMessageDialog(this, "Arquivo inválido! Conjunto ômega ausente!", "Erro", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		String[] omega = scan.next().split(",");
		
//		if(omega.length != CalculoProposicionalAntigo.CONJUNTO_OMEGA_PADRAO.length)
//		{
//			JOptionPane.showMessageDialog(this, "Arquivo inválido! Conjunto ômega corrompido!", "Erro", JOptionPane.ERROR_MESSAGE);
//			return;
//		}
		
//		if(CalculoProposicionalAntigo.checaConjuntoOmegaValido(omega) == false)
//		{
//			JOptionPane.showMessageDialog(this, "Arquivo inválido! Conjunto ômega inválido!", "Erro", JOptionPane.ERROR_MESSAGE);
//			return;
//		}
		
		calculoProposicionalAtual = new CalculoProposicional();
//		calculoProposicionalAtual.conectivosLogicos = omega;
		
		if( ! scan.hasNext())
		{
			JOptionPane.showMessageDialog(this, "Arquivo inválido! Conjunto alfa ausente!", "Erro", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		String[] alfa_string = scan.next().split(",");
		
//		if( calculoProposicionalAtual.checaConjuntoAlfaValido(alfa_string) == false )
//		{
//			JOptionPane.showMessageDialog(this, "Arquivo inválido! Conjunto alfa inválido!", "Erro", JOptionPane.ERROR_MESSAGE);
//			return;
//		}
		
		TreeSet<Character> alfa = new TreeSet<Character>();
		for(String s : alfa_string)
			alfa.add(s.charAt(0));
		
//		calculoProposicionalAtual.setConjuntoAlfa(alfa.toArray(new Character[0]));
		
		if( ! scan.hasNext())
		{
			JOptionPane.showMessageDialog(this, "Arquivo inválido! Formula corrompida!", "Erro", JOptionPane.ERROR_MESSAGE);
			return;
		}
		
		String formula = scan.next();
		
		try 
		{
//			formulaAtual = calculoProposicionalAtual.new Formula(formula);
		} 
		catch (Exception e) 
		{
			JOptionPane.showMessageDialog(this, "Fómula inválida! "+e.getMessage(), "Erro", JOptionPane.ERROR_MESSAGE);
		}
		
		//TODO atualizar GUI
	}

}
